home *** CD-ROM | disk | FTP | other *** search
- ; SPRITE routines
- MAX_SPRITE EQU 100
-
- RECTANGLE STRUCT 2,NONUNIQUE
- X WORD 0
- Y WORD 0
- Wid4 BYTE 0
- Ht BYTE 0
- Color BYTE 0
- Next WORD 0
- ; DrawMe is used to not bother with sprites that you know
- ; are contained totally within another, allowing animated
- ; eyes, etc to be stored in separate sprites. These will be
- ; drawn to the local buffer but skipped when copying to the
- ; screen, so if they are not TOTALLY contained, they will
- ; just get clipped away.
- DrawMe BYTE 1 ; default, yes draw me.
- ; (Storage from this point on ... NEVER provide anything but
- ; default for these values!)
- address_virt WORD 0
- address_buf WORD 0
- next_line_virt WORD 0
- next_line_buf WORD 0
- RECTANGLE ENDS
-
- SPRITE STRUCT 2, NONUNIQUE
- RECTANGLE <> ; Contains rectangle info
- SPRITE ENDS
-
- EVEN
- rect5 SPRITE <<40 ,60 , 2,8, C_TRANSPARENT, 0 , 0>>
- rect4 SPRITE <<80 ,30 , 2,8, C_TRANSPARENT, offset rect5, 0>>
- rect3 SPRITE <<120,60 , 2,8, C_TRANSPARENT, offset rect4, 0>>
- rect2 SPRITE <<55 ,100, 2,8, C_TRANSPARENT, offset rect3, 0>>
- rect1 SPRITE <<105,100, 2,8, C_TRANSPARENT, offset rect2, 0>>
-
- rect6 SPRITE <<36 ,56 , 4,16, C_BLUE, offset rect1, 1>>
- rect7 SPRITE <<76 ,26 , 4,16, C_BLUE, offset rect6, 1>>
- rect8 SPRITE <<116,56 , 4,16, C_BLUE, offset rect7, 1>>
- rect9 SPRITE <<51 ,96 , 4,16, C_BLUE, offset rect8, 1>>
- rect10 SPRITE <<101,96 , 4,16, C_BLUE, offset rect9, 1>>
-
- ;; Simply adding in these 5 rectangles (~20000 pixels for both
- ;; drawing and erasing) really slows things down! That's why
- ;; it's important to optimize the sprite drawing routines!
- rect11 SPRITE <<35 ,55 ,14,36, C_GREEN, offset rect10, 1>>
- rect12 SPRITE <<75 ,25 ,14,36, C_GREEN, offset rect11, 1>>
- rect13 SPRITE <<115,55 ,14,36, C_GREEN, offset rect12, 1>>
- rect14 SPRITE <<50 ,95 ,14,36, C_GREEN, offset rect13, 1>>
- rect15 SPRITE <<100,95 ,14,36, C_GREEN, offset rect14, 1>>
-
- FIRST_SPRITE EQU rect10
-
- EVEN
- AnimateSprites PROC near
- ret
- ; Blank out the draw page, by copying from the blank page
- ; to the draw page all rectangles which had changed. The
- ; blank page must always be entirely blank if this is going
- ; to work!
- mov di,cs:DrawPage.UpperLeftAddress
- add di,cs:DrawPage.ScrollOffset
- mov si,cs:BlankPage.UpperLeftAddress
- add si,cs:BlankPage.ScrollOffset
- mov bp,cs:BlankPage.Rectangles
- call CopyRectangles
-
- ; Now draw the sprites. Uses a temporary buffer to ensure
- ; minimal drawing to the screen, but that's not really necessary,
- ; if memory is at a minimum. It's just faster...
- mov bp,offset FIRST_SPRITE
- mov cs:DrawPage.Rectangles,bp
- call do_fill_buffer
- mov di,cs:DrawPage.UpperLeftAddress
- add di,cs:DrawPage.ScrollOffset
- mov bh,cs:DrawPage.AlignmentMask
- mov bp,offset FIRST_SPRITE
- jmp smart_rects ; "call"
- AnimateSprites ENDP
-
- smart_dest DW 0
- out_di DW 0
- out_si DW 0
-
- EVEN
- smart_rects PROC near
- add di,cs:DrawPage.Address
- mov ds,cs:segBuffer
- mov es,cs:segVideo
- mov dx,3c4h
- mov al,02h
- out dx,al
- inc dx
- mov cs:smart_dest,di
-
- ; === Beginning of loop through rectangles! ===
- sp_nextrect:
- cmp cs:[bp].RECTANGLE.DrawMe,1
- jne sp_next
- ; Draw this rectangle from the buffer to screen memory.
- ; Calculate the output address.
- mov si,cs:[bp].RECTANGLE.address_buf
- mov di,cs:[bp].RECTANGLE.address_virt
- add di,cs:smart_dest
-
- ; Loop over 4 planes
- mov bl,4
- sp_plane_loop: mov al,bh
- out dx,al
-
- mov cs:out_di,di
- mov cs:out_si,si
-
- ; Loop over height
- mov ch,cs:[bp].RECTANGLE.Ht
- sp_row_loop:
-
- ; Loop over width of rectangle (Wid4 is actually width/4)
- mov cl,cs:[bp].RECTANGLE.Wid4
- sp_col_loop:
-
- ; Read a byte from the buffer
- ; Is it transparent (no-modify)? If so, just jump over the draw
- mov al,byte ptr ds:[si]
- cmp al,C_TRANSPARENT
- je sp_next_pixel
- ; Otherwise, draw it on the spreen, and mark it transparent
- ; so that it won't be drawn again.
- mov byte ptr es:[di],al
- mov byte ptr ds:[si],C_TRANSPARENT
-
- ; Skip to next 4-byte group (next column that can be drawn in
- ; Mode X) Also increment spreen draw address, but only by 1
- ; because ModeX is 4 pixels per byte
- sp_next_pixel:
- add si,4
- inc di
-
- dec cl
- jnz sp_col_loop
-
- ; End of row. Skip space to get to left edge of next row down
- ; Skip SI = (SCREEN_WIDTH - #bytesdrawn)
- ; Only draw up to height of rectangle
- add si,cs:[bp].RECTANGLE.next_line_buf
- add di,cs:[bp].RECTANGLE.next_line_virt
- dec ch
- jnz sp_row_loop
-
- mov di,cs:out_di
- mov si,cs:out_si
- inc si
- rol bh,1
- adc di,0
-
- dec bl
- jnz sp_plane_loop
-
- ; Follow chain to next rectangle
- sp_next: mov bp,cs:[bp].RECTANGLE.Next
- cmp bp,0
- jne sp_nextrect
- ; All done
- sp_end: ret
- smart_rects ENDP
-
- ; BP -> first rectangle. Follows BP->next, stops when BP = 0
- EVEN
- do_fill_buffer PROC near
- mov es,cs:segBuffer
-
- cmp bp,0
- je fill_end
- fill_loop:
-
- mov bx,cs:[bp].RECTANGLE.Y
- shl bx,1 ; BX = word index y
- mov di,cs:MultBufWidth[bx] ; DI = SW * y
- mov cx,cs:[bp].RECTANGLE.X ; CX = x
- add di,cx ; DI = (SW * y) + x
- mov cs:[bp].RECTANGLE.address_buf,di ; (DI used later)
-
- mov ax,cs:MultVirtWidth[bx] ; AX = (VW/4) * y
- shr cx,2 ; CX = (x / 4)
- add ax,cx ; AX = (VW * y + x)/4
- mov cs:[bp].RECTANGLE.address_virt,ax
-
- mov dx,(VIRTUAL_WIDTH / 4)
- sub dl,cs:[bp].RECTANGLE.Wid4 ; DX = (VW - w) / 4
- mov cs:[bp].RECTANGLE.next_line_virt,dx
-
- mov dx,(SCREEN_WIDTH / 4)
- sub dl,cs:[bp].RECTANGLE.Wid4 ; DX = (SW - w) / 4
- shl dx,2 ; DX = SW - w
- mov cs:[bp].RECTANGLE.next_line_buf,dx
-
- mov ah,cs:[bp].RECTANGLE.Color
- mov al,cs:[bp].RECTANGLE.Color
-
- mov ch,cs:[bp].RECTANGLE.Ht
- fill_row_loop: mov cl,cs:[bp].RECTANGLE.Wid4
- fill_col_loop: mov es:[di],ax
- mov es:[di+2],ax
- add di,4
- dec cl
- jnz fill_col_loop
- add di,dx
- dec ch
- jnz fill_row_loop
-
- mov bp,cs:[bp].RECTANGLE.Next
- cmp bp,0
- jne fill_loop
- fill_end: ret
- do_fill_buffer ENDP
-
- EVEN
- CopyRectangles PROC near
- mov ax,cs:segVideo
- mov ds,ax
- mov es,ax
-
- ; Calculate the difference between the source and destination
- ; pages. Since in a movsb loop the two would remain a constant
- ; distance apart, we can just calculate a displacement and then
- ; not have to worry about SI; instead use DI and DI+BX, thanks
- ; to the thoughtful x86 ALU!
- mov bx,di
- sub bx,si
-
- mov dx,GC_INDEX
- mov ax,ALL_COPY_BITS
- out dx,ax
-
- mov dx,SC_INDEX
- mov ax,0F02h
- out dx,ax
- mov si,di ;store destination
-
- ; === Beginning of loop through rectangles! ===
- cr_nextrect: cmp cs:[bp].RECTANGLE.DrawMe,1
- jne cr_next
- ; Draw this rectangle from the buffer to screen memory.
- ; Calculate the output address.
- mov di,cs:[bp].RECTANGLE.address_virt
- mov dx,cs:[bp].RECTANGLE.next_line_virt
- add di,si
-
- ; Loop over height
- mov ch,cs:[bp].RECTANGLE.Ht
- cr_row_loop:
-
- ; Loop over width of rectangle (Wid4 is actually width/4)
- mov cl,cs:[bp].RECTANGLE.Wid4
- cr_col_loop: mov al,ds:[di + bx]
- stosb
- dec cl
- jnz cr_col_loop
- mov al,ds:[di + bx]
- mov es:[di],al
-
- ; End of row. Skip space to get to left edge of next row down
- ; Only draw up to height of rectangle
- add di,dx
- dec ch
- jnz cr_row_loop
-
- ; Follow chain to next rectangle
- cr_next: mov bp,cs:[bp].RECTANGLE.Next
- cmp bp,0
- jne cr_nextrect
- ; All done
- cr_end:
- mov dx,GC_INDEX
- mov ax,ALL_DRAW_BITS
- out dx,ax
- ret
- CopyRectangles ENDP
-